﻿


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using NetWork.IMessage;

namespace NetWork
{
    /// <summary>
    /// 本系统所有网络类的基类，该类为抽象类，无法进行实例化
    /// </summary>
    public abstract class NetworkBase
    {
        protected Socket CoreSocket = null;
        public Guid Token { get; set; }
        protected int TimeOut = 10000;//超时时间
        public NetworkBase()
        {
            Token = Guid.Empty;
        }
        /// <summary>
        /// 检查网络套接字是否操作超时，需要对套接字进行封装
        /// </summary>
        /// <param name="obj">通常是 <see cref="HslTimeOut"/> 对象 </param>
        protected void ThreadPoolCheckTimeOut(object obj)
        {
            HslTimeOut timeout = (HslTimeOut)obj;
            if (timeout != null)
            {
                while (!timeout.IsSuccessful)
                {
                    Thread.Sleep(100);
                    if ((DateTime.Now - timeout.StartTime).TotalMilliseconds > timeout.DelayTime)
                    {
                        // 连接超时或是验证超时
                        if (!timeout.IsSuccessful)
                        {
                            if (timeout.Operator != null) timeout.Operator.Invoke();
                            if (timeout.WorkSocket != null) timeout.WorkSocket.Close();
                        }
                        break;
                    }
                }
            }
        }
        /*****************************************************************************
       * 
       *    说明：
       *    下面的三个模块代码指示了如何接收数据，如何发送数据，如何连接网络
       * 
       ********************************************************************************/
        #region Reveive Content
        /// <summary>
        /// 接收固定长度的字节数组
        /// </summary>
        /// <remarks>
        /// Receive Special Length Bytes
        /// </remarks>
        /// <param name="socket">网络通讯的套接字</param>
        /// <param name="length">准备接收的数据长度</param>
        /// <returns>包含了字节数据的结果类</returns>
        protected Result<byte[]> Receive(Socket socket, int length)
        {
            if (length == 0) return Result.CreateSuccessResult(new byte[0]);
            var result = new Result<byte[]>();
            var receiveDone = new ManualResetEvent(false);
            var state = new StateObject(length);
            try
            {
                state.WaitDone = receiveDone;
                state.WorkSocket = socket;
                socket.BeginReceive(state.Buffer, state.AlreadyDealLength,
                    state.DataLength - state.AlreadyDealLength, SocketFlags.None,
                    new AsyncCallback(ReceiveCallback), state);
            }
            catch (Exception ex)
            {
                result.Message = ex.Message;
                receiveDone.Close();
                socket.Close();
                return result;
            }
            // 等待接收完成，或是发生异常
            receiveDone.WaitOne();
            receiveDone.Close();
            // 接收数据失败
            if (state.IsError)
            {
                socket.Close();
                result.Message = state.ErrerMsg;
                return result;
            }
            // 远程关闭了连接
            if (state.IsClose)
            {
                result.Success = false;
                result.Message = "远程关闭了连接";
                socket.Close();
                return result;
            }
            // 正常接收到数据
            result.Data = state.Buffer;
            result.Success = true;
            state.Clear();
            state = null;
            return result;
        }
        private void ReceiveCallback(IAsyncResult ar)
        {
            StateObject state = null;
            try
            {
                state = (StateObject)ar.AsyncState;
                Socket client = state.WorkSocket;
                int bytesRead = client.EndReceive(ar);
                if (bytesRead > 0)
                {
                    // 接收到了数据
                    state.AlreadyDealLength += bytesRead;
                    if (state.AlreadyDealLength < state.DataLength)
                    {
                        // 获取接下来的所有的数据
                        client.BeginReceive(state.Buffer, state.AlreadyDealLength,
                            state.DataLength - state.AlreadyDealLength, SocketFlags.None,
                            new AsyncCallback(ReceiveCallback), state);
                    }
                    else
                    {
                        // 接收到了所有的数据，通知接收数据的线程继续
                        state.WaitDone.Set();
                    }
                }
                else
                {
                    // 对方关闭了网络通讯
                    state.IsClose = true;
                    state.WaitDone.Set();
                }
            }
            catch (Exception ex)
            {
                Logger.LogError(ToString(), ex);
                if (state != null)
                {
                    state.IsError = true;
                    state.ErrerMsg = ex.Message;
                    state.WaitDone.Set();
                }
            }

        }
        #endregion
        #region Receive Message
        /// <summary>
        /// 接收一条完整的数据，使用异步接收完成，包含了指令头信息
        /// </summary>
        /// <param name="socket">已经打开的网络套接字</param>
        /// <param name="timeOut">超时时间</param>
        /// <param name="netMsg">消息规则</param>
        /// <returns>数据的接收结果对象</returns>
        protected Result<TNetMessage> ReceiveMessage<TNetMessage>(Socket socket, int timeOut, TNetMessage netMsg)
            where TNetMessage : INetMessage
        {
            Result<TNetMessage> result = new Result<TNetMessage>();
            // 超时接收的代码验证
            HslTimeOut hslTimeOut = new HslTimeOut()
            {
                DelayTime = timeOut,
                WorkSocket = socket,
            };
            if (timeOut > 0) ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCheckTimeOut), hslTimeOut);
            // 接收指令头
            Result<byte[]> headResult = Receive(socket, netMsg.ProtocolHeadBytesLength);
            if (!headResult.Success)
            {
                hslTimeOut.IsSuccessful = true;
                result.CopyErrorFromOther(headResult);
                return result;
            }
            netMsg.HeadBytes = (byte[])headResult.Data;
            if (!netMsg.CheckHeadBytesLegal(Token.ToByteArray()))
            {
                // 令牌校验失败
                hslTimeOut.IsSuccessful = true;
                socket.Close();
                Logger.LogError(ToString() + "接收验证令牌不一致");
               result.Message = "接收验证令牌不一致";
                return result;
            }
            int contentLength = netMsg.GetContentLengthByHeadBytes();
            if (contentLength == 0)
            {
                netMsg.ContentBytes = new byte[0];
            }
            else
            {
                Result<byte[]> contentResult = Receive(socket, contentLength);
                if (!contentResult.Success)
                {
                    hslTimeOut.IsSuccessful = true;
                    result.CopyErrorFromOther(contentResult);
                    return result;
                }
                netMsg.ContentBytes = (byte[])contentResult.Data;
            }
            // 防止没有实例化造成后续的操作失败
            if (netMsg.ContentBytes == null) netMsg.ContentBytes = new byte[0];
            hslTimeOut.IsSuccessful = true;
            result.Data = netMsg;
            result.Success = true;
            return result;
        }
        #endregion
        #region Send Content
        /// <summary>
        /// 发送消息给套接字，直到完成的时候返回
        /// </summary>
        /// <param name="socket">网络套接字</param>
        /// <param name="data">字节数据</param>
        /// <returns>发送是否成功的结果</returns>
        protected Result Send(Socket socket, byte[] data)
        {
            if (data == null) return Result.CreateSuccessResult();
            var result = new Result();
            var sendDone = new ManualResetEvent(false);
            var state = new StateObject(data.Length);
            try
            {
                state.WaitDone = sendDone;
                state.WorkSocket = socket;
                state.Buffer = data;
                socket.BeginSend(state.Buffer, state.AlreadyDealLength, state.DataLength - state.AlreadyDealLength,
                    SocketFlags.None, new AsyncCallback(SendCallBack), state);
            }
            catch (Exception ex)
            {
                // 发生了错误，直接返回
                Logger.LogError(ToString() , ex);
                result.Message = ex.Message;
                socket.Close();
                sendDone.Close();
                return result;
            }
            // 等待发送完成
            sendDone.WaitOne();
            sendDone.Close();
            if (state.IsError)
            {
                socket.Close();
                result.Message = state.ErrerMsg;
                return result;
            }
            state.Clear();
            state = null;
            result.Success = true;
            result.Message = "成功";
            return result;
        }
        /// <summary>
        /// 发送数据异步返回的方法
        /// </summary>
        /// <param name="ar">异步对象</param>
        private void SendCallBack(IAsyncResult ar)
        {
            StateObject state = (StateObject)ar.AsyncState;
            if (state != null)
            {
                try
                {
                    Socket socket = state.WorkSocket;
                    int byteSend = socket.EndSend(ar);
                    state.AlreadyDealLength += byteSend;
                    if (state.AlreadyDealLength < state.DataLength)
                    {
                        // 继续发送数据
                        socket.BeginSend(state.Buffer, state.AlreadyDealLength, state.DataLength - state.AlreadyDealLength,
                            SocketFlags.None, new AsyncCallback(SendCallBack), state);
                    }
                    else
                    {
                        // 发送完成
                        state.WaitDone.Set();
                    }
                }
                catch (Exception ex)
                {
                    // 发生了异常
                    state.IsError = true;
                    Logger.LogError(ToString(), ex);
                    state.ErrerMsg = ex.Message;
                    state.WaitDone.Set();
                }
            }
        }
        #endregion
        #region Socket Connect
        /// <summary>
        /// 创建一个新的socket对象并连接到远程的地址，默认超时时间为10秒钟
        /// </summary>
        /// <param name="ipAddress">Ip地址</param>
        /// <param name="port">端口号</param>
        /// <returns>返回套接字的封装结果对象</returns>
        protected Result<Socket> CreateSocketAndConnect(string ipAddress, int port)
        {
            return CreateSocketAndConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), TimeOut);
        }
        /// <summary>
        /// 创建一个新的socket对象并连接到远程的地址
        /// </summary>
        /// <param name="ipAddress">Ip地址</param>
        /// <param name="port">端口号</param>
        /// <param name="timeOut">连接的超时时间</param>
        /// <returns>返回套接字的封装结果对象</returns>
        protected Result<Socket> CreateSocketAndConnect(string ipAddress, int port, int timeOut)
        {
            return CreateSocketAndConnect(new IPEndPoint(IPAddress.Parse(ipAddress), port), timeOut);
        }
        /// <summary>
        /// 创建一个新的socket对象并连接到远程的地址
        /// </summary>
        /// <param name="endPoint">连接的目标终结点</param>
        /// <param name="timeOut">连接的超时时间</param>
        /// <returns>返回套接字的封装结果对象</returns>
        protected Result<Socket> CreateSocketAndConnect(IPEndPoint endPoint, int timeOut)
        {
            var result = new Result<Socket>();
            var connectDone = new ManualResetEvent(false);
            var state = new StateObject();
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // 超时验证的信息
            HslTimeOut connectTimeout = new HslTimeOut()
            {
                WorkSocket = socket,
                DelayTime = timeOut
            };
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadPoolCheckTimeOut), connectTimeout);
            try
            {
                state.WaitDone = connectDone;
                state.WorkSocket = socket;
                socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallBack), state);
            }
            catch (Exception ex)
            {
                connectTimeout.IsSuccessful = true;
                socket.Close();
                connectDone.Close();
                result.Success = false;
                result.Message = "连接失败：" + ex.Message;
                return result;
            }
            // 等待连接完成
            connectDone.WaitOne();
            connectDone.Close();
            connectTimeout.IsSuccessful = true;
            if (state.IsError)
            {
                result.Success = false;
                result.Message = "连接失败：" + state.ErrerMsg;
                socket.Close();
                return result;
            }
            state.Clear();
            state = null;
            result.Data = socket;
            result.Message = "连接成功";
            result.Success = true;
            return result;
        }
        /// <summary>
        /// 当连接的结果返回
        /// </summary>
        /// <param name="ar">异步对象</param>
        private void ConnectCallBack(IAsyncResult ar)
        {
            StateObject state = (StateObject)ar.AsyncState;
            if (state != null)
            {
                try
                {
                    Socket socket = state.WorkSocket;
                    socket.EndConnect(ar);
                    state.WaitDone.Set();
                }
                catch (Exception ex)
                {
                    state.IsError = true;
                    state.ErrerMsg = ex.Message;
                    state.WaitDone.Set();
                }
            }
        }
        #endregion
        /*****************************************************************************
         * 
         *    说明：
         *    下面的两个模块代码指示了如何读写文件
         * 
         ********************************************************************************/
        #region Read Stream
        /// <summary>
        /// 读取流中的数据到缓存区
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="buffer">缓冲区</param>
        /// <returns>带有成功标志的读取数据长度</returns>
        protected Result<int> ReadStream(Stream stream, byte[] buffer)
        {
            ManualResetEvent WaitDone = new ManualResetEvent(false);
            FileStateObject stateObject = new FileStateObject
            {
                WaitDone = WaitDone,
                Stream = stream,
                DataLength = buffer.Length,
                Buffer = buffer
            };
            try
            {
                stream.BeginRead(buffer, 0, stateObject.DataLength, new AsyncCallback(ReadStreamCallBack), stateObject);
            }
            catch (Exception ex)
            {
                Logger.LogError(ToString(), ex);
                stateObject = null;
                WaitDone.Close();
                return new Result<int>();
            }
            WaitDone.WaitOne();
            WaitDone.Close();
            if (stateObject.IsError)
            {
                return new Result<int>()
                {
                    Message = stateObject.ErrerMsg
                };
            }
            else
            {
                return Result.CreateSuccessResult(stateObject.AlreadyDealLength);
            }
        }
        private void ReadStreamCallBack(IAsyncResult ar)
        {
            if (ar.AsyncState is FileStateObject)
            {
                FileStateObject stateObject = (FileStateObject)ar.AsyncState;
                try
                {
                    stateObject.AlreadyDealLength += stateObject.Stream.EndRead(ar);
                    stateObject.WaitDone.Set();
                }
                catch (Exception ex)
                {
                    Logger.LogError(ToString(), ex);
                    stateObject.IsError = true;
                    stateObject.ErrerMsg = ex.Message;
                    stateObject.WaitDone.Set();
                }
            }
        }
        #endregion
        #region Write Stream
        /// <summary>
        /// 将缓冲区的数据写入到流里面去
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="buffer">缓冲区</param>
        /// <returns>是否写入成功</returns>
        protected Result WriteStream(Stream stream, byte[] buffer)
        {
            ManualResetEvent WaitDone = new ManualResetEvent(false);
            FileStateObject stateObject = new FileStateObject
            {
                WaitDone = WaitDone,
                Stream = stream
            };
            try
            {
                stream.BeginWrite(buffer, 0, buffer.Length, new AsyncCallback(WriteStreamCallBack), stateObject);
            }
            catch (Exception ex)
            {
                Logger.LogError(ToString(), ex);
                stateObject = null;
                WaitDone.Close();
                return new Result();
            }
            WaitDone.WaitOne();
            WaitDone.Close();
            if (stateObject.IsError)
            {
                return new Result()
                {
                    Message = stateObject.ErrerMsg
                };
            }
            else
            {
                return Result.CreateSuccessResult();
            }
        }
        private void WriteStreamCallBack(IAsyncResult ar)
        {
            FileStateObject stateObject = null;
            try
            {
                stateObject = (FileStateObject)ar.AsyncState;
                stateObject.Stream.EndWrite(ar);
            }
            catch (Exception ex)
            {
                stateObject.IsError = true;
                stateObject.ErrerMsg = ex.Message;
            }
            finally
            {
                stateObject.WaitDone.Set();
            }
        }
        #endregion
        #region Object Override
        /// <summary>
        /// 返回表示当前对象的字符串
        /// </summary>
        /// <returns>字符串</returns>
        public override string ToString()
        {
            return "NetworkBase->" + Token;
        }
        #endregion
    }
    /// <summary>
    /// 文件传送的异步对象
    /// </summary>
    internal class FileStateObject : StateOneBase
    {
        /// <summary>
        /// 操作的流
        /// </summary>
        public Stream Stream { get; set; }
    }
    /// <summary>
    /// 异步消息的对象
    /// </summary>
    internal class StateOneBase
    {
        /// <summary>
        /// 本次接收或是发送的数据长度
        /// </summary>
        public int DataLength { get; set; }
        /// <summary>
        /// 已经处理的字节长度
        /// </summary>
        public int AlreadyDealLength { get; set; }
        /// <summary>
        /// 操作完成的信号
        /// </summary>
        public ManualResetEvent WaitDone { get; set; }
        /// <summary>
        /// 缓存器
        /// </summary>
        public byte[] Buffer { get; set; }
        /// <summary>
        /// 是否发生了错误
        /// </summary>
        public bool IsError { get; set; }
        /// <summary>
        /// 错误消息
        /// </summary>
        public string ErrerMsg { get; set; }
    }
    /// <summary>
    /// 网络中的异步对象
    /// </summary>
    internal class StateObject : StateOneBase
    {
        #region Constructor
        /// <summary>
        /// 实例化一个对象
        /// </summary>
        public StateObject()
        {
        }
        /// <summary>
        /// 实例化一个对象，指定接收或是发送的数据长度
        /// </summary>
        /// <param name="length"></param>
        public StateObject(int length)
        {
            DataLength = length;
            Buffer = new byte[length];
        }
        /// <summary>
        /// 唯一的一串信息
        /// </summary>
        public string UniqueId { get; set; }
        #endregion
        #region Public Member
        /// <summary>
        /// 网络套接字
        /// </summary>
        public Socket WorkSocket { get; set; }
        /// <summary>
        /// 是否关闭了通道
        /// </summary>
        public bool IsClose { get; set; }
        #endregion
        #region Public Method
        /// <summary>
        /// 清空旧的数据
        /// </summary>
        public void Clear()
        {
            IsError = false;
            IsClose = false;
            AlreadyDealLength = 0;
            Buffer = null;
        }
        #endregion
    }
    internal class HslTimeOut
    {
        /// <summary>
        /// 实例化对象
        /// </summary>
        public HslTimeOut()
        {
            StartTime = DateTime.Now;
            IsSuccessful = false;
            HybirdLock = new SimpleHybirdLock();
        }
        /// <summary>
        /// 操作的开始时间
        /// </summary>
        public DateTime StartTime { get; set; }
        /// <summary>
        /// 操作是否成功
        /// </summary>
        public bool IsSuccessful { get; set; }
        /// <summary>
        /// 延时的时间，单位毫秒
        /// </summary>
        public int DelayTime { get; set; }
        /// <summary>
        /// 连接超时用的Socket
        /// </summary>
        public Socket WorkSocket { get; set; }
        /// <summary>
        /// 用于超时执行的方法
        /// </summary>
        public Action Operator { get; set; }
        /// <summary>
        /// 当前对象判断的同步锁
        /// </summary>
        public SimpleHybirdLock HybirdLock { get; set; }
    }
}
